/**
 * Represents the Cookie Monster character and implements his appetite needs
 * 
 * @author SNelson
 * 
 */
public class CookieMonster extends Thread implements Schedulable
{
	/**
	 * The vending machine that Cookie Monster visits
	 */
	private final VendingMachine machine;
	/**
	 * The scheduler that notifies us of time events
	 */
	private final Scheduler scheduler;

	/**
	 * The first hour that cookie monster will purchase a cookie
	 */
	public static final int COOKIE_TIME_1 = 11;
	/**
	 * The second hour that cookie monster will purchase a cookie
	 */
	public static final int COOKIE_TIME_2 = 23;
	/**
	 * The indent to use when printing Cookie Monster's messages
	 */
	public static final String INDENT = "    ";
	/**
	 * The name to use when printing
	 */
	public static final String NAME = "Cookie Monster";

	/**
	 * How many cookies Cookie Monster should purchase when he gets the chance
	 */
	private int cookiesToEat = 0;

	/**
	 * Whether or not Cookie Monster thread should stop
	 */
	private boolean stop = false;

	/**
	 * Constructor
	 * 
	 * @param scheduler
	 *            The scheduler that notifies this
	 * @param machine
	 *            The vending machine that Cookie Monster visits
	 */
	public CookieMonster(Scheduler scheduler, VendingMachine machine)
	{
		this.scheduler = scheduler;
		scheduler.addSchedulable(this);
		this.machine = machine;
		setName(NAME);
	}

	/**
	 * Called when a new day starts
	 * 
	 * @param day
	 *            The numeric day in the simulation
	 */
	@Override
	public void onNewDay(int day)
	{
	}

	/**
	 * Called when a new hour begins
	 * 
	 * @param day
	 *            The numeric day in the simulation
	 * @param hour
	 *            The hour of the day
	 */
	@Override
	public void onHour(final int day, final int hour)
	{
		if (hour == COOKIE_TIME_1 || hour == COOKIE_TIME_2)
		{
			synchronized (this)
			{
				cookiesToEat++;
				notifyAll();
			}
		}
	}

	/**
	 * Called when the simulation should end
	 */
	public synchronized void onSimulationEnd()
	{
		scheduler.removeSchedulable(this);
		stop = true;
		notifyAll();
	}

	/**
	 * Body of this thread
	 */
	@Override
	public void run()
	{
		while (!stop)
		{
			synchronized (this)
			{
				try
				{
					wait();
				}
				catch (InterruptedException e)
				{
					e.printStackTrace();
				}

				if (stop)
				{
					return;
				}

				while (cookiesToEat > 0)
				{
					VendingMachineTransaction.Builder builder = new VendingMachineTransaction.Builder(
						machine);
					VendingMachineTransaction transaction = builder
						.doSomething(new Runnable()
						{
							@Override
							public void run()
							{
								print("Attempting to purchase a cookie");
							}
						}).purchaseCookie().build();
					boolean success = machine.executeTransaction(transaction);
					if (success)
					{
						print("Me love cookies");
					}
					else
					{
						print("Me hungry");
					}
					cookiesToEat--;
				}
			}
		}
	}

	/**
	 * Prints the given contents formatted for Cookie Monster
	 * 
	 * @param contents
	 *            The contents to print
	 */
	private void print(String contents)
	{
		System.out.println(INDENT + scheduler.getFormattedTime() + " "
			+ getName() + ": " + contents);
	}
}
